<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>xeokit Example</title>
    <link href="../css/pageStyle.css" rel="stylesheet"/>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.13.0/js/all.min.js"></script>
</head>
<body>
<input type="checkbox" id="info-button"/>
<label for="info-button" class="info-button"><i class="far fa-3x fa-question-circle"></i></label>
<canvas id="myCanvas"></canvas>
<div class="slideout-sidebar">
    <img class="info-icon" src="../../assets/images/performance_model_icon.png"/>
    <h1>SceneModel</h1>
    <h2>Geometry instancing benchmark</h2>
    <p>In this example, we're building a large model using xeokit's SceneModel component and geometry instancing.</p>
    <p>Reusing geometry speeds up rendering and reduces the memory footprint.</p>
    <ul>
        <li>
            <div id="pleaseWait">Geometry batching benchmark<br>generating 373494 objects, please wait...</div>
        </li>
    </ul>
    <h3>Components Used</h3>
    <ul>
        <li>
            <a href="../../docs/class/src/viewer/Viewer.js~Viewer.html"
               target="_other">Viewer</a>
        </li>
        <li>
            <a href="../../docs/class/src/viewer/scene/model/SceneModel.js~SceneModel.html"
               target="_other">SceneModel</a>
        </li>
    </ul>
</div>
</body>

<script type="module">

    //------------------------------------------------------------------------------------------------------------------
    // Import the modules we need for this example
    //------------------------------------------------------------------------------------------------------------------

    import {Viewer,SceneModel,buildBoxGeometry} from "../../dist/xeokit-sdk.min.es.js";

    //------------------------------------------------------------------------------------------------------------------
    // Create a Viewer and arrange the camera
    //------------------------------------------------------------------------------------------------------------------

    const viewer = new Viewer({
        canvasId: "myCanvas",
        transparent: true,
        lodEnabled: true
    });

    viewer.scene.camera.perspective.far = 10000;

    viewer.scene.camera.eye = [-2760.80, 606.64, -1098.80];
    viewer.scene.camera.look = [-106.46, -434.89, -171.60];
    viewer.scene.camera.up = [0.32, 0.92, 0.11];

    viewer.scene.highlightMaterial.edges = false;


    //------------------------------------------------------------------------------------------------------------------
    // Activate LoD
    //------------------------------------------------------------------------------------------------------------------

    // viewer.scene.lod.enabled = true;
    // viewer.scene.lod.targetFPS = 100; // Excessive value to force LoD
 //   viewer.scene.lod.lodLevels = [2000, 600, 150, 80, 10];

    //------------------------------------------------------------------------------------------------------------------
    // Generate the buildings
    //------------------------------------------------------------------------------------------------------------------

    viewer.scene.canvas.spinner.processes += 1;

    const sceneModel = new SceneModel(viewer.scene, {
        id: "table",
        isModel: true, // <----------------- Represents a model, registers SceneModel by ID on viewer.scene.models
        position: [0, 0, 0],
        scale: [1, 1, 1],
        rotation: [0, 0, 0],
        edges: false,
        colorTextureEnabled: false
    });

    // Create a reusable geometry within the SceneModel

    sceneModel.createGeometry(buildBoxGeometry({
        id: "myBoxGeometry",
        xSize: 1,
        ySize: 1,
        zSize: 1
    }));

    var numObjects = 0;

    const numObjectsSpan = document.getElementById("numObjects");
    const pleaseWaitSpan = document.getElementById("pleaseWait");

    function makeBuilding(xmin, zmin, xmax, zmax) {

        var xpos = (xmin + xmax) * 0.5;
        var ypos = 0;
        var zpos = (zmin + zmax) * 0.5;

        // Now generate the building as a bunch of boxes

        var yMaxSize = (Math.random() * 10) + 10;
        var ySize = yMaxSize;
        var width;
        var axis;
        var sign;

        var xminBox;
        var zminBox;
        var xmaxBox;
        var zmaxBox;

        while (ySize > 2) {
            width = (Math.random() * 5) + 2;
            axis = Math.round(Math.random());
            sign = Math.round(Math.random());
            switch (axis) {
                case 0:
                    if (sign === 0) {
                        xminBox = xmin;
                        zminBox = zpos - width;
                        xmaxBox = xpos + width;
                        zmaxBox = zpos + width;
                    } else {
                        xminBox = xpos - width;
                        zminBox = zpos - width;
                        xmaxBox = xmax;
                        zmaxBox = zpos + width;
                    }
                    break;

                case 1:
                    if (sign === 0) {
                        xminBox = xpos - width;
                        zminBox = zmin;
                        xmaxBox = xpos + width;
                        zmaxBox = zpos + width;
                    } else {
                        xminBox = xpos - width;
                        zminBox = zpos - width;
                        xmaxBox = xpos + width;
                        zmaxBox = zmax;
                    }
                    break;
            }

            const meshId = "mesh" + numObjects++;

            sceneModel.createMesh({
                id: meshId,
                geometryId: "myBoxGeometry",
                position: [xpos, ypos + ySize, zpos],
                scale: [(xmaxBox - xminBox) * 0.5, ySize, (zmaxBox - zminBox) * 0.5],
                rotation: [0, 0, 0],
                color: [0.3 + Math.random() * 0.5, 0.3 + Math.random() * 0.5, 0.3 + Math.random() * 0.5, 1.0]
            });

            sceneModel.createEntity({
                meshIds: [meshId],
                isObject: true // <--- Represents an object, registers Entity by ID on viewer.scene.objects
            });

            // Decrease current vertical box size
            ySize -= (Math.random() * 2) + .5;
        }
    }

    var extent = 1500;
    var x = -extent;
    var z = -extent;
    var done = false;

    function nextBuilding() {
        if (done) {
            return;
        }
        if (z < extent) {
            if (x < extent) {
                x += 20;
            } else {
                x = -extent;
                z += 20;
            }
            makeBuilding(x + 2, z + 2, x + 5 - 2, z + 5 - 2);
        } else {
            pleaseWaitSpan.innerHTML += "preparing model..";
            sceneModel.finalize();
            const pleaseWait = document.getElementById("pleaseWait");
            pleaseWait.parentElement.removeChild(pleaseWait);
            viewer.scene.canvas.spinner.processes -= 1;

            // viewer.scene.on("tick", () => {
            //     viewer.camera.orbitYaw(0.4);
            // });

            done = true;
        }
    }

    function run() {
        for (var i = 0; i < 1000; i++) {
            nextBuilding();
        }

        if (!done) {
            setTimeout(run);
        }
    }

    run();

</script>
</html>